import json
import sys
import tkinter as tk
from tkinter import messagebox

# Define the Student class
class Student:
    def __init__(self, fullname, student_id=None):
        self.name = fullname
        self.student_id = student_id
        self.borrowed_books = []
        self.credit = 3

    def borrow_book(self, book):
        count = 0
        for _ in self.borrowed_books:
            count += 1
        if count < 7:
            self.borrowed_books.append(book)
            book.borrow_count += 1
            book.available = False
            return True
        return False

    def return_book(self, book):
        index = 0
        while index < len(self.borrowed_books):
            if self.borrowed_books[index] == book:
                del self.borrowed_books[index]
                book.available = True
                if book.waitlist:
                    next_student = book.waitlist.pop(0)
                    next_student.borrow_book(book)
                return True
            index += 1
        return False

    def lose_book(self):
        self.credit -= 1

# Define the Book class
class Book:
    book_id = 1

    def __init__(self, title, authors, year):
        self.id = Book.book_id
        Book.book_id += 1
        self.title = title
        self.authors = authors
        self.year = year
        self.available = True
        self.waitlist = []
        self.borrow_count = 0

    def __eq__(self, other):
        return self.id == other.id

# Define the BookCount class
class BookCount:
    def __init__(self, book, count):
        self.book = book
        self.count = count

# Define the Library class
class Library:
    def __init__(self):
        self.catalog = []
        self.students = []

    def add_book(self, book):
        self.catalog.append(book)

    def remove_book(self, book):
        index = 0
        while index < len(self.catalog):
            if self.catalog[index] == book:
                del self.catalog[index]
                break
            index += 1

    def search_books(self, title=None, authors=None, year=None):
        result = []
        for book in self.catalog:
            if (title and title in book.title) or \
                    (authors and authors in book.authors) or \
                    (year and year == book.year):
                result.append(book)
        return result

    def get_most_borrowed_books(self):
        book_counts = []
        for book in self.catalog:
            found = False
            index = 0
            while index < len(book_counts):
                if book_counts[index].book == book:
                    book_counts[index].count = book.borrow_count
                    found = True
                    break
                index += 1
            if not found:
                book_counts.append(BookCount(book, book.borrow_count))

        for i in range(len(book_counts)):
            for j in range(i + 1, len(book_counts)):
                if book_counts[i].count < book_counts[j].count:
                    book_counts[i], book_counts[j] = book_counts[j], book_counts[i]

        return [book_count.book for book_count in book_counts]

# Define the function to load book data from a file
def load_courses_from_file(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            book_data = json.load(file)
        book_list = book_data.get("books", [])
        library_books = []
        for data in book_list:
            if not all(key in data for key in ["title", "authors", "year"]):
                continue
            new_book = Book(
                title=data["title"],
                authors=data["authors"],
                year=data["year"]
            )
            library_books.append(new_book)
        return library_books
    except FileNotFoundError:
        messagebox.showerror("Error", f"File not found: {file_path}")
        sys.exit(1)
    except json.JSONDecodeError:
        messagebox.showerror("Error", f"JSON file format error: {file_path}")
        sys.exit(1)
    except Exception as e:
        messagebox.showerror("Error", f"Error loading book data: {str(e)}")
        sys.exit(1)

# Define the function to load student data from a file
def load_students_from_file(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            student_data = json.load(file)
        students_list = student_data.get("students", [])
        library_students = []
        for data in students_list:
            if isinstance(data, dict):
                if "fullName" not in data:
                    continue
                new_student = Student(
                    fullname=data["fullName"],
                    student_id=data.get("username", None)
                )
                new_student.credit = data.get("credit", 3)
                library_students.append(new_student)
        return library_students
    except FileNotFoundError:
        messagebox.showerror("Error", f"File not found: {file_path}")
        return []
    except json.JSONDecodeError:
        messagebox.showerror("Error", f"JSON file format error: {file_path}")
        return []
    except Exception as e:
        messagebox.showerror("Error", f"Error loading student data: {e}")
        return []

# Specify the absolute file paths
COURSE_JSON_PATH = r"resources\courses.json"
STUDENT_JSON_PATH = r"resources\students.json"

# Create a library instance
library = Library()
# Load book data
courses = load_courses_from_file(COURSE_JSON_PATH)
for book in courses:
    library.add_book(book)
# Load student data
students = load_students_from_file(STUDENT_JSON_PATH)
library.students = students

# GUI function for searching books
def search_books_gui(library, text_widget):
    title = title_entry.get()
    authors = authors_entry.get()
    year = year_entry.get()
    if year:
        try:
            year = int(year)
        except ValueError:
            messagebox.showerror("Error", "Invalid year input, please enter a number.")
            return
    result = library.search_books(title, authors, year)
    text_widget.delete(1.0, tk.END)
    if result:
        text_widget.insert(tk.END, "Search results:\n")
        for book in result:
            status = "Available" if book.available else "Borrowed"
            text_widget.insert(tk.END, f"ID: {book.id}, Title: {book.title}, Authors: {book.authors}, Year: {book.year}, Status: {status}\n")
    else:
        text_widget.insert(tk.END, "No relevant books found.")

# GUI function for borrowing books
def borrow_book_gui(library, text_widget, student_id_entry):
    student_id = student_id_entry.get()
    student = next((s for s in library.students if s.student_id == student_id), None)
    if not student:
        messagebox.showerror("Error", "Student not found.")
        return
    book_id = book_id_entry.get()
    try:
        book_id = int(book_id)
    except ValueError:
        messagebox.showerror("Error", "Invalid book ID input, please enter a number.")
        return
    book = next((b for b in library.catalog if b.id == book_id), None)
    if not book:
        messagebox.showerror("Error", "Book not found.")
        return
    if student.borrow_book(book):
        messagebox.showinfo("Success", f"{student.name} successfully borrowed {book.title}")
    else:
        messagebox.showerror("Failure", f"{student.name} failed to borrow {book.title}, reached the borrowing limit.")

# GUI function for returning books
def return_book_gui(library, text_widget):
    student_id = student_id_return_entry.get()
    student = next((s for s in library.students if s.student_id == student_id), None)
    if not student:
        messagebox.showerror("Error", "Student not found.")
        return
    book_id = book_id_return_entry.get()
    try:
        book_id = int(book_id)
    except ValueError:
        messagebox.showerror("Error", "Invalid book ID input, please enter a number.")
        return
    book = next((b for b in library.catalog if b.id == book_id), None)
    if not book:
        messagebox.showerror("Error", "Book not found.")
        return
    if student.return_book(book):
        messagebox.showinfo("Success", f"{student.name} successfully returned {book.title}")
    else:
        messagebox.showerror("Failure", f"{student.name} did not borrow {book.title}, cannot return.")

# GUI function for viewing the most borrowed books
def get_most_borrowed_books_gui(library, text_widget):
    books = library.get_most_borrowed_books()
    text_widget.delete(1.0, tk.END)
    if books:
        text_widget.insert(tk.END, "Most borrowed books:\n")
        for book in books:
            text_widget.insert(tk.END, f"ID: {book.id}, Title: {book.title}, Authors: {book.authors}, Year: {book.year}, Borrow count: {book.borrow_count}\n")
    else:
        text_widget.insert(tk.END, "No borrowing records yet.")

# Create the main window
root = tk.Tk()
root.title("Library Management System")

# Search books section
tk.Label(root, text="Search Books").grid(row=0, column=0, columnspan=2)
tk.Label(root, text="Title:").grid(row=1, column=0)
title_entry = tk.Entry(root)
title_entry.grid(row=1, column=1)
tk.Label(root, text="Authors:").grid(row=2, column=0)
authors_entry = tk.Entry(root)
authors_entry.grid(row=2, column=1)
tk.Label(root, text="Year:").grid(row=3, column=0)
year_entry = tk.Entry(root)
year_entry.grid(row=3, column=1)
search_button = tk.Button(root, text="Search", command=lambda: search_books_gui(library, result_text))
search_button.grid(row=4, column=0, columnspan=2)

# Borrow books section
tk.Label(root, text="Borrow Books").grid(row=5, column=0, columnspan=2)
tk.Label(root, text="Student ID:").grid(row=6, column=0)
student_id_entry = tk.Entry(root)
student_id_entry.grid(row=6, column=1)
tk.Label(root, text="Book ID:").grid(row=7, column=0)
book_id_entry = tk.Entry(root)
book_id_entry.grid(row=7, column=1)
borrow_button = tk.Button(root, text="Borrow", command=lambda: borrow_book_gui(library, result_text, student_id_entry))
borrow_button.grid(row=8, column=0, columnspan=2)

# Return books section
tk.Label(root, text="Return Books").grid(row=9, column=0, columnspan=2)
tk.Label(root, text="Student ID:").grid(row=10, column=0)
student_id_return_entry = tk.Entry(root)
student_id_return_entry.grid(row=10, column=1)
tk.Label(root, text="Book ID:").grid(row=11, column=0)
book_id_return_entry = tk.Entry(root)
book_id_return_entry.grid(row=11, column=1)
return_button = tk.Button(root, text="Return", command=lambda: return_book_gui(library, result_text))
return_button.grid(row=12, column=0, columnspan=2)

# View most borrowed books section
tk.Label(root, text="View Most Borrowed Books").grid(row=13, column=0, columnspan=2)
most_borrowed_button = tk.Button(root, text="View", command=lambda: get_most_borrowed_books_gui(library, result_text))
most_borrowed_button.grid(row=14, column=0, columnspan=2)

# Result display section
result_text = tk.Text(root, height=10, width=50)
result_text.grid(row=15, column=0, columnspan=2)

# Run the main loop
root.mainloop()